S3バケットにアップロードされたファイルを Lambda で Box にアップロードしてみる
はじめに
おはようございます、もきゅりんです。
Shall we box ?
タイトルのような検証があったため、ついでにブログにしておきました。
どっかでまた Box に関わることがあるかもしれないので、 Box の概念などをまとめておきたかった次第です。
やること
S3にファイルがアップロードされるイベントから、そのファイルをBoxにアップロードする、シンプルな仕組みです。
その他、非同期で実行される Lambda くんが3回失敗すると、DLQ から SNS を経由して、担当者にメールが届くような仕組みになります。
まずは Box をドキュメントに沿って理解していきます。
なお、説明とか興味なく、利用してみたいだけなんだが、という方は 下記 Box の設定を対応していただき、
GitHub リポジトリ にCDK リソースをあげていますので README および下記 CDK でリソースを構築する を参考に実行ください。
(Box SDK の型定義付けは、 こちら で頑張るぞ、と進行形のようです。)
Box Platform の理解
Box での設定をする前にある程度、概念を理解しておきます。
下記、開発者向けの Box の全般的なガイドに沿って理解を進めていきます。
(Box というサービスとは別に、APIを利用してBox の機能を拡張する仕様を Box Platform と称するようです。)
Boxユーザーの種類
Box というサービス上の管理者が各ユーザを管理作成するように、Box Platform において管理者権限をもつエンティティを サービスアカウント と呼び、サービスアカウントによって App User を承認し、管理作成します。
アプリケーションがサービスアカウント(サーバー認証を利用するアプリケーション)として生成されるには、Box というサービス上の管理者に承認される必要があります。
上記の関係は下図で示されています。
ユーザーモデル
- ユーザーモデル - Box開発者向けドキュメントポータル では従来型、 App User 、サービスアカウント、システム対システムといった様々なユーザーモデルがありますが、本稿では従来型のユーザーモデルで対応します。
その他モデルについては上記リンクを参照下さい。
アプリケーションには、管理対象となる従来の Box の内部ユーザーおよび App User の外部ユーザーが存在します。
コンテンツの所有者は、アプリケーションサービスアカウントまたは管理対象ユーザーが該当します。
従来型のユーザーモデルは下図です。
Box platform アプリケーションの種類
3つのアプリケーションの種類から選択します。
選択するアプリケーションの種類は、プロジェクトのユースケースによって決まり、アプリケーションの構成時に使用できる認証方法のみに影響します。
この選択を後で変更することはできません。
- アプリの種類の選択 - Box開発者向けドキュメントポータル を参照します。
今回のケースでは、Box Viewを利用したり、別のアプリケーション内でBoxコンテンツをプレビューしたりしませんし、Boxにアップロードされたファイルに対してカスタマイズした処理を実行しません。
ということで、カスタムアプリ一択になります。
(後述しますが、 そもそも Box 公式 SDK の JWT 認証を利用する場合、カスタムアプリケーション一択になります。)
認証方法
カスタムアプリでは、 OAuth 2.0、JWT、またはクライアント資格情報許可 の3つの方法があります。
- 認証方法の選択 - Box開発者向けドキュメントポータル を参照します。
今回のケースでは、 Lambda が実行主体です。
つまり、エンドユーザーによる操作が必要ありません。
選択肢は、 JWT かクライアント資格情報許可になりますが、
今回利用する Box 公式 SDK には、JWT 認証のサポートが組み込まれているため、素直に JWT 認証を選択します。
なお、JWTを使用するサーバー側の認証は、アプリの種類がカスタムアプリケーションの場合のみ使用できます。
- SDKを使用したJWT - Box開発者向けドキュメントポータル の前提条件に記載されている通り、以下を対応します。
- 開発者コンソール内でBoxアプリケーションを作成する
- アプリケーション用に秘密キーの構成ファイルを作成してダウンロードし、config.jsonとして保存する
- 社内で使用するためにBoxアプリケーションが承認されていることを確認する
3 の承認については、JWTまたはクライアント資格情報許可を使用するサーバー認証アプリケーションは、使用前にBox管理者が承認する必要があります。
- カスタムアプリの承認 - Box開発者向けドキュメントポータル の通り、手動による承認通知を実行します。
これでサービスアカウントとしてカスタムアプリを実行できるようになります。
ここまで理解できたら、実際に 1、2、3 の設定をしていきます。
Box の設定
1 開発者コンソール内でBoxアプリケーションを作成
マイアプリ > アプリの新規作成からカスタムアプリを作成します。認証方法はサーバ認証(JWT使用)です。
アプリの作成すると次のイメージになります。
構成画面のアプリケーションスコープで書き込み権限を追加します。
2 アプリケーション用に秘密キーの構成ファイルを作成してダウンロードし、config.jsonとして保存
公開/秘密キーペアを生成しようとすると怒られるので
管理コンソール > Enterprise設定 > セキュリティから2段階ログイン認証を設定します。
改めて公開/秘密キーペアを生成してファイルをダウンロードします。
このファイルは SSM パラメータストアに格納するので大事大事にして下さい。
3. 社内で使用するためにBoxアプリケーションが承認されていることを確認
アプリケーションの承認タブから確認して送信を押下します。
管理者の元にメールが届くので承認してもらいます。
承認後、アプリケーションの承認ページでステータスが表示されます。
アプリケーションが管理コンソールで承認される前に、ユーザーがサービスアカウントアクセストークンを使用してAPI呼び出しを実行しようとすると、次のエラーメッセージが表示されます。
"error":"unauthorized_client" "error_description": "This app is not authorized by the enterprise"
フォルダにユーザーを招待
この段階で、フォルダにテキトーなファイルをアップロードしてフォルダを確認しようとしても何も見ることはできません。
割りとわかりにくい表現なのですが、サービスアカウント-フォルダツリーとコラボレーション では下記のように記載されています。
サービスアカウントは、アプリケーションをEnterprise内のユーザーとして表すため、独自のフォルダツリーとコンテンツ所有権の機能が用意されています。最初は、所有するコンテンツやコラボレーションするコンテンツがないため、このフォルダツリーはデフォルトで空になっています。
(中略)
既存のコンテンツでのコラボレーションにサービスアカウントを追加するには、他のユーザーの場合と同様、割り当てられたメールアドレスを使用してサービスアカウントを招待する必要があります。
テキトーなフォルダを作成します。
開発者コンソールから一般設定タブのサービスアカウント情報のメールアドレスを使ってユーザー招待することができます。
なお、 クラウドストレージ「Box」にAPIを使ってファイルをアップロードする - Qiita のように、管理者コンソールからグループを作成して、ユーザー追加して共有フォルダを作成する方が、個別にユーザー追加していく方法よりも、明示的に管理することができるので適切だと考えます。
CDK でリソースを構築する
ここまで進めたら、SDK を使って フォルダ内の項目のリストを取得 することで、フォルダIDも取得できます。
GitHub リポジトリ からプルしてREADMEを参考に進めます。
SSM パラメータの SecureString で BoxConfigParams
と BoxFolderID
にそれぞれ config.json の内容を、さきほどカスタムアプリに共有したフォルダのIDを格納します。
(フォルダIDは、フォルダのURLからも確認できます)
あとは CDK をデプロイします。
作成されたS3に box
というフォルダを作成してその配下に何かファイルをアップロードします。
小さいテキストファイルをアップロードします。
今後は若干重めの mp4 ファイルをアップロードします。
Box にアップロードされていますでしょうか。
これら2つのアップロードには、 直接ファイルアップロードおよび分割アップロードの 2つの API を使い分けて対応しています。
詳細は、 アップロード - Box開発者向けドキュメントポータル を参照下さい。
わざと失敗させてみる
サブスクリプションの確認がメールで来ているはずなので、確認しましょう。
以下のようにフォルダIDを誤った値に変更して再度 CDK をデプロイして、上と同じように S3 にファイルをアップロードしてみましょう。
// lambda/index.ts line45 const ssmBoxFolderRes = await ssmClient.send( - new GetParameterCommand(ssmInput('BoxFolderID')) + new GetParameterCommand(ssmInput('9999999')) );
メールが届きましたでしょうか。
以上です。
どなたかの参考になれば幸いです。
P.S. ヨッシー 、 パス操作に関するモジュールを秒で教えてくれてありがとう!